From b2bef9fe49a040c3a60568e26deb723098597a1f Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Tue, 7 Dec 2010 18:27:40 +0000 Subject: [PATCH] amd xsave: Enable XSAVE/XRSTOR for SVM guest This patch creates a common interface hanlding xsetbv. Signed-off-by: Wei Huang --- xen/arch/x86/hvm/hvm.c | 25 +++++++++++++++++++++++++ xen/arch/x86/hvm/svm/emulate.c | 2 ++ xen/arch/x86/hvm/svm/svm.c | 7 +++++++ xen/arch/x86/hvm/vmx/vmx.c | 26 +------------------------- xen/include/asm-x86/hvm/support.h | 2 ++ xen/include/asm-x86/hvm/svm/emulate.h | 1 + xen/include/asm-x86/hvm/svm/vmcb.h | 1 + 7 files changed, 39 insertions(+), 25 deletions(-) diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 544286a1ff..91bcb92997 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -1144,6 +1144,31 @@ bool_t hvm_hap_nested_page_fault(unsigned long gfn) return 0; } +int hvm_handle_xsetbv(u64 new_bv) +{ + struct vcpu *v = current; + struct segment_register sreg; + + hvm_get_segment_register(v, x86_seg_ss, &sreg); + if ( sreg.attr.fields.dpl != 0 ) + goto err; + + if ( ((new_bv ^ xfeature_mask) & ~xfeature_mask) || !(new_bv & 1) ) + goto err; + + if ( (xfeature_mask & XSTATE_YMM & new_bv) && !(new_bv & XSTATE_SSE) ) + goto err; + + v->arch.xcr0 = new_bv; + v->arch.xcr0_accum |= new_bv; + set_xcr0(new_bv); + + return 0; +err: + hvm_inject_exception(TRAP_gp_fault, 0, 0); + return -1; +} + int hvm_set_efer(uint64_t value) { struct vcpu *v = current; diff --git a/xen/arch/x86/hvm/svm/emulate.c b/xen/arch/x86/hvm/svm/emulate.c index 2537dd2445..87da614491 100644 --- a/xen/arch/x86/hvm/svm/emulate.c +++ b/xen/arch/x86/hvm/svm/emulate.c @@ -101,6 +101,7 @@ MAKE_INSTR(HLT, 1, 0xf4); MAKE_INSTR(INT3, 1, 0xcc); MAKE_INSTR(RDTSC, 2, 0x0f, 0x31); MAKE_INSTR(PAUSE, 1, 0x90); +MAKE_INSTR(XSETBV, 3, 0x0f, 0x01, 0xd1); static const u8 *opc_bytes[INSTR_MAX_COUNT] = { @@ -114,6 +115,7 @@ static const u8 *opc_bytes[INSTR_MAX_COUNT] = [INSTR_INT3] = OPCODE_INT3, [INSTR_RDTSC] = OPCODE_RDTSC, [INSTR_PAUSE] = OPCODE_PAUSE, + [INSTR_XSETBV] = OPCODE_XSETBV, }; static int fetch(struct vcpu *v, u8 *buf, unsigned long addr, int len) diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index aefaabc415..074d61229e 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -1600,6 +1600,13 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs *regs) hvm_inject_exception(TRAP_invalid_op, HVM_DELIVER_NO_ERROR_CODE, 0); break; + case VMEXIT_XSETBV: + if ( (inst_len = __get_instruction_length(current, INSTR_XSETBV))==0 ) + break; + if ( hvm_handle_xsetbv((((u64)regs->edx) << 32) | regs->eax) == 0 ) + __update_guest_eip(regs, inst_len); + break; + case VMEXIT_NPF: perfc_incra(svmexits, VMEXIT_NPF_PERFC); regs->error_code = vmcb->exitinfo1; diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 2dd14b4fd7..f89428d60e 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -2194,30 +2194,6 @@ static int vmx_handle_eoi_write(void) return 0; } -static int vmx_handle_xsetbv(u64 new_bv) -{ - struct vcpu *v = current; - struct segment_register sreg; - - hvm_get_segment_register(v, x86_seg_ss, &sreg); - if ( sreg.attr.fields.dpl != 0 ) - goto err; - - if ( ((new_bv ^ xfeature_mask) & ~xfeature_mask) || !(new_bv & 1) ) - goto err; - - if ( (xfeature_mask & XSTATE_YMM & new_bv) && !(new_bv & XSTATE_SSE) ) - goto err; - - v->arch.xcr0 = new_bv; - v->arch.xcr0_accum |= new_bv; - set_xcr0(new_bv); - return 0; -err: - vmx_inject_hw_exception(TRAP_gp_fault, 0); - return -1; -} - asmlinkage void vmx_vmexit_handler(struct cpu_user_regs *regs) { unsigned int exit_reason, idtv_info, intr_info = 0, vector = 0; @@ -2610,7 +2586,7 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs *regs) case EXIT_REASON_XSETBV: { u64 new_bv = (((u64)regs->edx) << 32) | regs->eax; - if ( vmx_handle_xsetbv(new_bv) == 0 ) + if ( hvm_handle_xsetbv(new_bv) == 0 ) update_guest_eip(); /* Safe: XSETBV */ break; } diff --git a/xen/include/asm-x86/hvm/support.h b/xen/include/asm-x86/hvm/support.h index d4377852a8..5a39aae0a9 100644 --- a/xen/include/asm-x86/hvm/support.h +++ b/xen/include/asm-x86/hvm/support.h @@ -128,6 +128,8 @@ void hvm_triple_fault(void); void hvm_rdtsc_intercept(struct cpu_user_regs *regs); +int hvm_handle_xsetbv(u64 new_bv); + /* These functions all return X86EMUL return codes. */ int hvm_set_efer(uint64_t value); int hvm_set_cr0(unsigned long value); diff --git a/xen/include/asm-x86/hvm/svm/emulate.h b/xen/include/asm-x86/hvm/svm/emulate.h index b06f98e06f..68d6d4972c 100644 --- a/xen/include/asm-x86/hvm/svm/emulate.h +++ b/xen/include/asm-x86/hvm/svm/emulate.h @@ -32,6 +32,7 @@ enum instruction_index { INSTR_INT3, INSTR_RDTSC, INSTR_PAUSE, + INSTR_XSETBV, INSTR_MAX_COUNT /* Must be last - Number of instructions supported */ }; diff --git a/xen/include/asm-x86/hvm/svm/vmcb.h b/xen/include/asm-x86/hvm/svm/vmcb.h index 990cbe64f9..10ff3945a0 100644 --- a/xen/include/asm-x86/hvm/svm/vmcb.h +++ b/xen/include/asm-x86/hvm/svm/vmcb.h @@ -299,6 +299,7 @@ enum VMEXIT_EXITCODE VMEXIT_MONITOR = 138, /* 0x8a */ VMEXIT_MWAIT = 139, /* 0x8b */ VMEXIT_MWAIT_CONDITIONAL= 140, /* 0x8c */ + VMEXIT_XSETBV = 141, /* 0x8d */ VMEXIT_NPF = 1024, /* 0x400, nested paging fault */ VMEXIT_INVALID = -1 }; -- 2.30.2